using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    /// <summary>
    /// 膳食记录仓储实现
    /// </summary>
    public class MealRecordRepository : Repository<MealRecord>, IMealRecordRepository
    {
        public MealRecordRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<MealRecord>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(m => m.UserId == userId).OrderByDescending(m => m.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<MealRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(m => m.UserId == userId && m.RecordDate >= startDate && m.RecordDate <= endDate).ToListAsync();
        }

        public async Task<IEnumerable<MealRecord>> GetByUserIdAndMealTypeAsync(Guid userId, string mealType)
        {
            return await _dbSet.Where(m => m.UserId == userId && m.MealType == mealType).ToListAsync();
        }

        public async Task<IEnumerable<MealRecord>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(m => m.RecordDate >= startDate && m.RecordDate <= endDate).ToListAsync();
        }

        public async Task<MealRecord?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(m => m.UserId == userId && m.RecordDate.Date == date.Date);
        }

        public async Task<Dictionary<string, int>> GetMealTypeStatisticsAsync(Guid userId, int days = 30)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var meals = await _dbSet
                .Where(m => m.UserId == userId && m.RecordDate >= startDate && m.RecordDate <= endDate)
                .GroupBy(m => m.MealType)
                .Select(g => new { MealType = g.Key, Count = g.Count() })
                .ToListAsync();

            return meals.ToDictionary(m => m.MealType, m => m.Count);
        }

        public async Task<double> GetAverageCaloriesAsync(Guid userId, int days = 7)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var meals = await _dbSet
                .Where(m => m.UserId == userId && m.RecordDate >= startDate && m.RecordDate <= endDate)
                .ToListAsync();

            return meals.Any() ? meals.Average(m => m.Calories) : 0;
        }
    }

    /// <summary>
    /// 食物信息仓储实现
    /// </summary>
    public class FoodInfoRepository : Repository<FoodInfo>, IFoodInfoRepository
    {
        public FoodInfoRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<FoodInfo?> GetByNameAsync(string name)
        {
            return await _dbSet.FirstOrDefaultAsync(f => f.Name == name);
        }

        public async Task<IEnumerable<FoodInfo>> GetByCategoryAsync(string category)
        {
            return await _dbSet.Where(f => f.Category == category).ToListAsync();
        }

        public async Task<IEnumerable<FoodInfo>> GetByNutritionAsync(string nutritionType, double minValue, double maxValue)
        {
            return await _dbSet.Where(f => 
                (nutritionType == "calories" && f.Calories >= minValue && f.Calories <= maxValue) ||
                (nutritionType == "protein" && f.Protein >= minValue && f.Protein <= maxValue) ||
                (nutritionType == "fat" && f.Fat >= minValue && f.Fat <= maxValue) ||
                (nutritionType == "carbohydrates" && f.Carbohydrates >= minValue && f.Carbohydrates <= maxValue))
                .ToListAsync();
        }

        public async Task<IEnumerable<FoodInfo>> GetRecommendedAsync(string lifeStage, string healthGoal)
        {
            return await _dbSet.Where(f => f.IsRecommended && 
                (f.RecommendedFor == lifeStage || f.RecommendedFor == "all") &&
                (f.HealthBenefit.Contains(healthGoal) || f.HealthBenefit == "general"))
                .ToListAsync();
        }

        public async Task<IEnumerable<FoodInfo>> GetBySeasonAsync(string season)
        {
            return await _dbSet.Where(f => f.Season == season || f.Season == "all").ToListAsync();
        }

        public async Task<IEnumerable<FoodInfo>> GetByRegionAsync(string region)
        {
            return await _dbSet.Where(f => f.Region == region || f.Region == "all").ToListAsync();
        }

        public async Task<IEnumerable<FoodInfo>> SearchAsync(string keyword)
        {
            return await _dbSet.Where(f => 
                f.Name.Contains(keyword) || 
                f.Description.Contains(keyword) || 
                f.Category.Contains(keyword))
                .ToListAsync();
        }
    }

    /// <summary>
    /// 食谱仓储实现
    /// </summary>
    public class RecipeRepository : Repository<Recipe>, IRecipeRepository
    {
        public RecipeRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Recipe>> GetByCategoryAsync(string category)
        {
            return await _dbSet.Where(r => r.Category == category).ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByDifficultyAsync(string difficulty)
        {
            return await _dbSet.Where(r => r.Difficulty == difficulty).ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByCookingTimeAsync(int maxMinutes)
        {
            return await _dbSet.Where(r => r.CookingTime <= maxMinutes).ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet.Where(r => r.SuitableFor == lifeStage || r.SuitableFor == "all").ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetByNutritionGoalAsync(string nutritionGoal)
        {
            return await _dbSet.Where(r => r.NutritionGoal == nutritionGoal || r.NutritionGoal == "general").ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetBySeasonAsync(string season)
        {
            return await _dbSet.Where(r => r.Season == season || r.Season == "all").ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> GetRecommendedAsync(string lifeStage, string healthGoal)
        {
            return await _dbSet.Where(r => r.IsRecommended && 
                (r.SuitableFor == lifeStage || r.SuitableFor == "all") &&
                (r.NutritionGoal == healthGoal || r.NutritionGoal == "general"))
                .ToListAsync();
        }

        public async Task<IEnumerable<Recipe>> SearchAsync(string keyword)
        {
            return await _dbSet.Where(r => 
                r.Name.Contains(keyword) || 
                r.Description.Contains(keyword) || 
                r.Category.Contains(keyword) ||
                r.Instructions.Contains(keyword))
                .ToListAsync();
        }
    }

    /// <summary>
    /// 食谱食材仓储实现
    /// </summary>
    public class RecipeIngredientRepository : Repository<RecipeIngredient>, IRecipeIngredientRepository
    {
        public RecipeIngredientRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<RecipeIngredient>> GetByRecipeIdAsync(Guid recipeId)
        {
            return await _dbSet.Where(i => i.RecipeId == recipeId).ToListAsync();
        }

        public async Task<IEnumerable<RecipeIngredient>> GetByFoodIdAsync(Guid foodId)
        {
            return await _dbSet.Where(i => i.FoodId == foodId).ToListAsync();
        }

        public async Task<Dictionary<Guid, List<RecipeIngredient>>> GetByRecipeIdsAsync(IEnumerable<Guid> recipeIds)
        {
            var ingredients = await _dbSet.Where(i => recipeIds.Contains(i.RecipeId)).ToListAsync();
            
            return ingredients
                .GroupBy(i => i.RecipeId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }
    }

    /// <summary>
    /// 营养目标仓储实现
    /// </summary>
    public class NutritionGoalRepository : Repository<NutritionGoal>, INutritionGoalRepository
    {
        public NutritionGoalRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<NutritionGoal?> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.FirstOrDefaultAsync(g => g.UserId == userId);
        }

        public async Task<NutritionGoal?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(g => g.UserId == userId && g.StartDate.Date <= date.Date && g.EndDate.Date >= date.Date);
        }

        public async Task<IEnumerable<NutritionGoal>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(g => g.UserId == userId && 
                ((g.StartDate >= startDate && g.StartDate <= endDate) || 
                 (g.EndDate >= startDate && g.EndDate <= endDate) ||
                 (g.StartDate <= startDate && g.EndDate >= endDate)))
                .ToListAsync();
        }

        public async Task<IEnumerable<NutritionGoal>> GetByGoalTypeAsync(string goalType)
        {
            return await _dbSet.Where(g => g.GoalType == goalType).ToListAsync();
        }

        public async Task<IEnumerable<NutritionGoal>> GetActiveGoalsAsync(Guid userId)
        {
            var today = DateTime.UtcNow.Date;
            return await _dbSet.Where(g => g.UserId == userId && g.StartDate.Date <= today && g.EndDate.Date >= today).ToListAsync();
        }
    }

    /// <summary>
    /// 饮水记录仓储实现
    /// </summary>
    public class WaterIntakeRepository : Repository<WaterIntake>, IWaterIntakeRepository
    {
        public WaterIntakeRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<WaterIntake>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(w => w.UserId == userId).OrderByDescending(w => w.RecordDate).ToListAsync();
        }

        public async Task<IEnumerable<WaterIntake>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(w => w.UserId == userId && w.RecordDate >= startDate && w.RecordDate <= endDate).ToListAsync();
        }

        public async Task<WaterIntake?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(w => w.UserId == userId && w.RecordDate.Date == date.Date);
        }

        public async Task<double> GetTotalAmountByDateAsync(Guid userId, DateTime date)
        {
            var records = await _dbSet.Where(w => w.UserId == userId && w.RecordDate.Date == date.Date).ToListAsync();
            return records.Sum(w => w.Amount);
        }

        public async Task<double> GetAverageAmountAsync(Guid userId, int days = 7)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-days);

            var records = await _dbSet
                .Where(w => w.UserId == userId && w.RecordDate >= startDate && w.RecordDate <= endDate)
                .ToListAsync();

            if (!records.Any())
                return 0;

            var totalAmount = records.Sum(w => w.Amount);
            return totalAmount / days;
        }

        public async Task<Dictionary<DateTime, double>> GetDailyAmountsAsync(Guid userId, int days = 7)
        {
            var endDate = DateTime.UtcNow.Date;
            var startDate = endDate.AddDays(-days);

            var records = await _dbSet
                .Where(w => w.UserId == userId && w.RecordDate >= startDate && w.RecordDate <= endDate)
                .ToListAsync();

            var result = new Dictionary<DateTime, double>();
            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                var dayRecords = records.Where(w => w.RecordDate.Date == date.Date);
                result[date] = dayRecords.Sum(w => w.Amount);
            }

            return result;
        }
    }

    /// <summary>
    /// 饮食计划仓储实现
    /// </summary>
    public class DietPlanRepository : Repository<DietPlan>, IDietPlanRepository
    {
        public DietPlanRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<DietPlan>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(d => d.UserId == userId).OrderByDescending(d => d.CreatedAt).ToListAsync();
        }

        public async Task<DietPlan?> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet.FirstOrDefaultAsync(d => d.UserId == userId && d.StartDate.Date <= date.Date && d.EndDate.Date >= date.Date);
        }

        public async Task<IEnumerable<DietPlan>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(d => d.UserId == userId && 
                ((d.StartDate >= startDate && d.StartDate <= endDate) || 
                 (d.EndDate >= startDate && d.EndDate <= endDate) ||
                 (d.StartDate <= startDate && d.EndDate >= endDate)))
                .ToListAsync();
        }

        public async Task<IEnumerable<DietPlan>> GetByLifeStageAsync(string lifeStage)
        {
            return await _dbSet.Where(d => d.LifeStage == lifeStage || d.LifeStage == "all").ToListAsync();
        }

        public async Task<IEnumerable<DietPlan>> GetByGoalTypeAsync(string goalType)
        {
            return await _dbSet.Where(d => d.GoalType == goalType).ToListAsync();
        }

        public async Task<IEnumerable<DietPlan>> GetActivePlansAsync(Guid userId)
        {
            var today = DateTime.UtcNow.Date;
            return await _dbSet.Where(d => d.UserId == userId && d.StartDate.Date <= today && d.EndDate.Date >= today).ToListAsync();
        }
    }

    /// <summary>
    /// 饮食计划项仓储实现
    /// </summary>
    public class DietPlanItemRepository : Repository<DietPlanItem>, IDietPlanItemRepository
    {
        public DietPlanItemRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<DietPlanItem>> GetByPlanIdAsync(Guid planId)
        {
            return await _dbSet.Where(i => i.PlanId == planId).OrderBy(i => i.MealTime).ToListAsync();
        }

        public async Task<IEnumerable<DietPlanItem>> GetByPlanIdAndDateAsync(Guid planId, DateTime date)
        {
            return await _dbSet.Where(i => i.PlanId == planId && i.Date.Date == date.Date).OrderBy(i => i.MealTime).ToListAsync();
        }

        public async Task<IEnumerable<DietPlanItem>> GetByPlanIdAndDateRangeAsync(Guid planId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet.Where(i => i.PlanId == planId && i.Date >= startDate && i.Date <= endDate).OrderBy(i => i.Date).ThenBy(i => i.MealTime).ToListAsync();
        }

        public async Task<IEnumerable<DietPlanItem>> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            var planIds = await _context.Set<DietPlan>()
                .Where(p => p.UserId == userId && p.StartDate.Date <= date.Date && p.EndDate.Date >= date.Date)
                .Select(p => p.Id)
                .ToListAsync();

            return await _dbSet.Where(i => planIds.Contains(i.PlanId) && i.Date.Date == date.Date).OrderBy(i => i.MealTime).ToListAsync();
        }

        public async Task<Dictionary<Guid, List<DietPlanItem>>> GetByPlanIdsAsync(IEnumerable<Guid> planIds)
        {
            var items = await _dbSet.Where(i => planIds.Contains(i.PlanId)).ToListAsync();
            
            return items
                .GroupBy(i => i.PlanId)
                .ToDictionary(g => g.Key, g => g.ToList());
        }
    }
}